﻿/*
===========================================================================

  Copyright (c) 2010-2014 Darkstar Dev Teams

  This program is free software: you can redistribute it and/or modify
  it under the terms of the GNU General Public License as published by
  the Free Software Foundation, either version 3 of the License, or
  (at your option) any later version.

  This program is distributed in the hope that it will be useful,
  but WITHOUT ANY WARRANTY; without even the implied warranty of
  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  GNU General Public License for more details.

  You should have received a copy of the GNU General Public License
  along with this program.  If not, see http://www.gnu.org/licenses/

  This file is part of DarkStar-server source code.

===========================================================================
*/

#include "../../common/utils.h"
#include "attackutils.h"
#include "battleutils.h"
#include "charutils.h"
#include "../packets/inventory_finish.h"
#include "../items.h"
#include "../attack.h"


namespace attackutils
{

/************************************************************************
*                                                                       *
*  Multihit calculator.											        *
*                                                                       *
************************************************************************/

uint8 getHitCount(uint8 hits)
{
    uint8 distribution = WELL512::irand()%100;
    uint8 num = 1;

	switch (hits)
    {
        case 0: break;
        case 1: break;
        case 2: // cdf = 55,100
			if(distribution < 55){ break; }
			else{ num+=1; break;}
			break;
		case 3: // cdf = 30,80,100
			if(distribution < 30){ break; }
			else if(distribution < 80){ num+=1; break; }
			else{ num+=2; break; }
			break;
        case 4: // cdf = 20,50,80,100
			if(distribution < 20){ break; }
			else if(distribution < 50){ num+=1; break; }
			else if(distribution < 80){ num+=2; break; }
			else{ num+=3; break; }
			break;
        case 5: // cdf = 10,30,60,90,100
			if(distribution < 10){ break; }
			else if(distribution < 30){ num+=1; break; }
			else if(distribution < 60){ num+=2; break; }
			else if(distribution < 90){ num+=3; break; }
			else{ num+=4; break; }
			break;
        case 6: // cdf = 10,30,50,70,90,100
            if(distribution < 10){ break; }
			else if(distribution < 30){num+=1; break; }
			else if(distribution < 50){num+=2; break; }
			else if(distribution < 70){num+=3; break; }
			else if(distribution < 90){num+=4; break; }
			else{ num+=5; break; }
            break;
        case 7: // cdf = 5,20,45,70,85,95,100
            if(distribution < 5){ break; }
			else if(distribution < 20){num+=1; break; }
			else if(distribution < 45){num+=2; break; }
			else if(distribution < 70){num+=3; break; }
			else if(distribution < 85){num+=4; break; }
			else if(distribution < 95){num+=5; break; }
			else{ num+=6; break; }
            break;
        case 8: // cdf = 5,20,45,70,85,95,98,100
			if(distribution < 5){ break; }
			else if(distribution < 20){num+=1; break; }
			else if(distribution < 45){num+=2; break; }
			else if(distribution < 70){num+=3; break; }
			else if(distribution < 85){num+=4; break; }
			else if(distribution < 95){num+=5; break; }
			else if(distribution < 98){num+=6; break; }
			else{ num+=7; break; }
            break;
	}
    return dsp_min(num,8); // не более восьми ударов за одну атаку
    // No more than eight strikes per attack
}

/************************************************************************
*                                                                       *
*  Is parried.													        *
*                                                                       *
************************************************************************/

bool IsParried(CBattleEntity* PAttacker, CBattleEntity* PDefender)
{
    if(isFaceing(PDefender->loc.p, PAttacker->loc.p, 40))
    {
        return (WELL512::irand() % 100 < battleutils::GetParryRate(PAttacker, PDefender));
    }
    return false;
}

/************************************************************************
*                                                                       *
*  Is guarded.													        *
*                                                                       *
************************************************************************/

bool IsGuarded(CBattleEntity* PAttacker, CBattleEntity* PDefender)
{
    if(isFaceing(PDefender->loc.p, PAttacker->loc.p, 40))
    {
        return(WELL512::irand() % 100 < battleutils::GetGuardRate(PAttacker, PDefender));
    }
    return false;
}

/************************************************************************
*                                                                       *
*  Is blocked.													        *
*                                                                       *
************************************************************************/

bool IsBlocked(CBattleEntity* PAttacker, CBattleEntity* PDefender)
{
	if(isFaceing(PDefender->loc.p, PAttacker->loc.p, 40))
    {
        return(WELL512::irand() % 100 < battleutils::GetBlockRate(PAttacker, PDefender));
    }
    return false;
}

/************************************************************************
*                                                                       *
*  Handles damage multiplier, relic weapons ect				            *
*                                                                       *
************************************************************************/

uint32 CheckForDamageMultiplier(CCharEntity* PChar, CItemWeapon* PWeapon, uint32 damage, PHYSICAL_ATTACK_TYPE attackType)
{
	if (PWeapon==NULL)
	{
		return damage;
	}
	uint32 originalDamage = damage;

	CItemWeapon* PAmmo = (CItemWeapon*)PChar->getEquip(SLOT_AMMO);

	switch (PWeapon->getID())
	{
		// Relic weapons have 16% (ffxiclopedia) chance to do x times damage, cannot proc with weapon skills

		// Relic: 2.5 times damage
		case 18264:		// Spharai 75
		case 18265:		// Spharai 80
		case 18637:		// Spharai 85
		case 18651:		// Spharai 90
		case 18665:		// Spharai 95
		case 19746:		// Spharai 99
		case 19839:		// Spharai 99-2
		case 20480:		// Spharai 99-3
		case 20481:		// Spharai 99-4

		case 18276:		// Excalibur 75
		case 18277:		// Excalibur 80
		case 18639:		// Excalibur 85
		case 18653:		// Excalibur 90
		case 18667:		// Excalibur 95
		case 19748:		// Excalibur 99
		case 19841:		// Excalibur 99-2
		case 20645:		// Excalibur 99-3
		case 20646:		// Excalibur 99-4

		case 18282:		// Ragnarok 75
		case 18283:		// Ragnarok 80
		case 18640:		// Ragnarok 85
		case 18654:		// Ragnarok 90
		case 18668:		// Ragnarok 95
		case 19749:		// Ragnarok 99
		case 19842:		// Ragnarok 99-2
		case 20745:		// Ragnarok 99-3
		case 20746:		// Ragnarok 99-4

		case 18288:		// Guttler 75
		case 18289:		// Guttler 80
		case 18641:		// Guttler 85
		case 18655:		// Guttler 90
		case 18669:		// Guttler 95
		case 19750:		// Guttler 99
		case 19843:		// Guttler 99-2
		case 20790:		// Guttler 99-3
		case 20791:		// Guttler 99-4

		case 18300:		// Gungnir 75
		case 18301:		// Gungnir 80
		case 18643:		// Gungnir 85
		case 18657:		// Gungnir 90
		case 18671:		// Gungnir 95
		case 19752:		// Gungnir 99
		case 19845:		// Gungnir 99-2
		case 20925:		// Gungnir 99-3
		case 20926:		// Gungnir 99-4

		case 18318:		// Amanomurakumo 75
		case 18319:		// Amanomurakumo 80
		case 18646:		// Amanomurakumo 85
		case 18660:		// Amanomurakumo 90
		case 18674:		// Amanomurakumo 95
		case 19755:		// Amanomurakumo 99
		case 19848:		// Amanomurakumo 99-2
		case 21015:		// Amanomurakumo 99-3
		case 21016:		// Amanomurakumo 99-4

		case 18330:		// Claustrum 75
		case 18331:		// Claustrum 80
		case 18648:		// Claustrum 85
		case 18662:		// Claustrum 90
		case 18676:		// Claustrum 95
		case 19757:		// Claustrum 99
		case 19850:		// Claustrum 99-2
		case 21135:		// Claustrum 99-3
		case 21136:		// Claustrum 99-4
			if (WELL512::irand()%100 <= 16)
			{
				originalDamage = (damage * (float)2.5);
			}
			break;

		// Relic: 3 times damage
		case 18270:		// Mandau 75
		case 18271:		// Mandau 80
		case 18638:		// Mandau 85
		case 18652:		// Mandau 90
		case 18666:		// Mandau 95
		case 19747:		// Mandau 99
		case 19840:		// Mandau 99-2
		case 20555:		// Mandau 99-3
		case 20556:		// Mandau 99-4

		case 18312:		// Kikoku 75
		case 18313:		// Kikoku 80
		case 18645:		// Kikoku 85
		case 18659:		// Kikoku 90
		case 18673:		// Kikoku 95
		case 19754:		// Kikoku 99
		case 19847:		// Kikoku 99-2
		case 20970:		// Kikoku 99-3
		case 20971:		// Kikoku 99-4

		case 18324:		// Mjollnir 75
		case 18325:		// Mjollnir 80
		case 18647:		// Mjollnir 85
		case 18661:		// Mjollnir 90
		case 18675:		// Mjollnir 95
		case 19756:		// Mjollnir 99
		case 19849:		// Mjollnir 99-2
		case 21060:		// Mjollnir 99-3
		case 21061:		// Mjollnir 99-4

		case 18336:		// Annihilator 75
		case 18337:		// Annihilator 80
		case 18649:		// Annihilator 85
		case 18663:		// Annihilator 90
		case 18677:		// Annihilator 95
		case 19758:		// Annihilator 99
		case 19851:		// Annihilator 99-2
		case 21260:		// Annihilator 99-3
		case 21261:		// Annihilator 99-4

		case 18348:		// Yoichinoyumi 75
		case 18349:		// Yoichinoyumi 80
		case 18650:		// Yoichinoyumi 85
		case 18664:		// Yoichinoyumi 90
		case 18678:		// Yoichinoyumi 95
		case 19759:		// Yoichinoyumi 99
		case 19852:		// Yoichinoyumi 99-2
		case 21210:		// Yoichinoyumi 99-3
		case 21211:		// Yoichinoyumi 99-4
			if (WELL512::irand()%100 <= 16)
			{
				originalDamage = (damage * 3);
			}
			break;

		// Relic: 2 times damage
		case 18294:		// Bravura 75
		case 18295:		// Bravura 80
		case 18642:		// Bravura 85
		case 18656:		// Bravura 90
		case 18670:		// Bravura 95
		case 19751:		// Bravura 99
		case 19844:		// Bravura 99-2
		case 20835:		// Bravura 99-3
		case 20836:		// Bravura 99-4

		case 18306:		// Apocalypse 75
		case 18307:		// Apocalypse 80
		case 18644:		// Apocalypse 85
		case 18658:		// Apocalypse 90
		case 18672:		// Apocalypse 95
		case 19753:		// Apocalypse 99
		case 19846:		// Apocalypse 99-2
		case 20880:		// Apocalypse 99-3
		case 20881:		// Apocalypse 99-4

			if (WELL512::irand()%100 <= 16)
			{
				originalDamage = (damage * 2);
			}
			break;

		// Aftermath Empyrean Weapons 2x Dmg
		case 19460:		// Farsha 85
		case 19538:		// Farsha 90
		case 19636:		// Farsha 95
		case 19809:		// Farsha 99
		case 19857:		// Farsha 99-2
		case 20794:		// Farsha 99-3
		case 20795:		// Farsha 99-4

		case 19461:		// Ukonvasara 85
		case 19539:		// Ukonvasara 90
		case 19637:		// Ukonvasara 95
		case 19810:		// Ukonvasara 99
		case 19858:		// Ukonvasara 99-2
		case 20839:		// Ukonvasara 99-3
		case 20840:		// Ukonvasara 99-4

		case 19466:		// Gambanteinn 85
		case 19544:		// Gambanteinn 90
		case 19642:		// Gambanteinn 95
		case 19815:		// Gambanteinn 99
		case 19863:		// Gambanteinn 99-2
		case 21064:		// Gambanteinn 99-3
		case 21065:		// Gambanteinn 99-4

		case 19457:		// Twashtar 85
		case 19535:		// Twashtar 90
		case 19633:		// Twashtar 95
		case 19806:		// Twashtar 99
		case 19854:		// Twashtar 99-2
		case 20563:		// Twashtar 99-3
		case 20564:		// Twashtar 99-4

		case 19456:		// Verethragna 85
		case 19534:		// Verethragna 90
		case 19632:		// Verethragna 95
		case 19805:		// Verethragna 99
		case 19853:		// Verethragna 99-2
		case 20486:		// Verethragna 99-3
		case 20487:		// Verethragna 99-4

		case 19464:		// Kannagi 85
		case 19542:		// Kannagi 90
		case 19640:		// Kannagi 95
		case 19813:		// Kannagi 99
		case 19861:		// Kannagi 99-2
		case 20974:		// Kannagi 99-3
		case 20975:		// Kannagi 99-4

		case 19465:		// Masamune 85
		case 19543:		// Masamune 90
		case 19641:		// Masamune 95
		case 19814:		// Masamune 99
		case 19862:		// Masamune 99-2
		case 21019:		// Masamune 99-3
		case 21020:		// Masamune 99-4

		case 19463:		// Rhongomiant 85
		case 19541:		// Rhongomiant 90
		case 19639:		// Rhongomiant 95
		case 19812:		// Rhongomiant 99
		case 19860:		// Rhongomiant 99-2
		case 20929:		// Rhongomiant 99-3
		case 20930:		// Rhongomiant 99-4

		case 19462:		// Redemption 85
		case 19540:		// Redemption 90
		case 19638:		// Redemption 95
		case 19811:		// Redemption 99
		case 19859:		// Redemption 99-2
		case 20884:		// Redemption 99-3
		case 20885:		// Redemption 99-4

		case 19467:		// Hvergelmir 85
		case 19545:		// Hvergelmir 90
		case 19643:		// Hvergelmir 95
		case 19816:		// Hvergelmir 99
		case 19864:		// Hvergelmir 99-2
		case 21143:		// Hvergelmir 99-3
		case 21144:		// Hvergelmir 99-4

		case 19458:		// Almace 85
		case 19536:		// Almace 90
		case 19634:		// Almace 95
		case 19807:		// Almace 99
		case 19855:		// Almace 99-2
		case 20653:		// Almace 99-3
		case 20654:		// Almace 99-4

		case 19459:		// Caladbolg 85
		case 19537:		// Caladbolg 90
		case 19635:		// Caladbolg 95
		case 19808:		// Caladbolg 99
		case 19856:		// Caladbolg 99-2
		case 20747:		// Caladbolg 99-3
		case 20748:		// Caladbolg 99-4

		case 19468:		// Gandiva 85
		case 19546:		// Gandiva 90
		case 19644:		// Gandiva 95
		case 19817:		// Gandiva 99
		case 19865:		// Gandiva 99-2
		case 21212:		// Gandiva 99-3
		case 21213:		// Gandiva 99-4

		case 19469:		// Armageddon 85
		case 19547:		// Armageddon 90
		case 19645:		// Armageddon 95
		case 19818:		// Armageddon 99
		case 19866:		// Armageddon 99-2
		case 21264:		// Armageddon 99-3
		case 21265:		// Armageddon 99-4

			if(PChar->StatusEffectContainer->HasStatusEffect(EFFECT_AFTERMATH_LV1) == true)
			{
				if (WELL512::irand()%100 <= 30)
				{
					// ShowDebug(CL_CYAN"Aftermath Lvl 1 Proc \n");
					originalDamage = (damage * 2);
				}
			}
			else if(PChar->StatusEffectContainer->HasStatusEffect(EFFECT_AFTERMATH_LV2) == true)
			{
				if (WELL512::irand()%100 <= 40)
				{
					// ShowDebug(CL_CYAN"Aftermath Lvl 2 Proc \n");
					originalDamage = (damage * 2);
				}
			}
			else if(PChar->StatusEffectContainer->HasStatusEffect(EFFECT_AFTERMATH_LV3) == true)
			{
				if (WELL512::irand()%100 <= 50)
				{
					// ShowDebug(CL_CYAN"Aftermath Lvl 3 Proc \n");
					originalDamage = (damage * 2);
				}
			}
			break;

		//mythic weapons, same distribution as multi attacking weapons

		// Aftermath Lvl 3 Mythic Weapons: 2x Dmg
		case 19001:		// Gastraphetes 75

		case 19007:		// Death Penalty 75

			if(PChar->StatusEffectContainer->HasStatusEffect(EFFECT_AFTERMATH_LV3) == true)
			{
				if (WELL512::irand()%100 <= 40)
				{
					// ShowDebug(CL_CYAN"Aftermath Lvl 3 2x Proc 40 Percent \n");
					originalDamage = (damage * 2);
				}
			}
			break;

		case 19070:		// Gastraphetes 80
		case 19090:		// Gastraphetes 85
		case 19622:		// Gastraphetes 90

		case 19076:		// Death Penalty 80
		case 19096:		// Death Penalty 85
		case 19628:		// Death Penalty 90

			if(PChar->StatusEffectContainer->HasStatusEffect(EFFECT_AFTERMATH_LV3) == true)
			{
				if (WELL512::irand()%100 <= 60)
				{
					// ShowDebug(CL_CYAN"Aftermath Lvl 3 2x Proc 60 Percent \n");
					originalDamage = (damage * 2);
				}
			}
			break;

		// Aftermath Lvl 3 Mythic Weapons: 2x-3x Dmg
		case 19720:		// Gastraphetes 95
		case 19829:		// Gastraphetes 99
		case 19958:		// Gastraphetes 99-2
		case 21246:		// Gastraphetes 99-3
		case 21247:		// Gastraphetes 99-4

		case 19726:		// Death Penalty 95
		case 19835:		// Death Penalty 99
		case 19964:		// Death Penalty 99-2
		case 21262:		// Death Penalty 99-3
		case 21263:		// Death Penalty 99-4

			if(PChar->StatusEffectContainer->HasStatusEffect(EFFECT_AFTERMATH_LV3) == true)
			{
				if (WELL512::irand()%100 <= 60)
				{
					// ShowDebug(CL_CYAN"Aftermath Lvl 3 2x-3x Proc 60 Percent \n");
					if (WELL512::irand()%100 < 50)
					{
						originalDamage = (damage * 2);
					}
					else
					{
						originalDamage = (damage * 3);
					}
				}
			}
			break;

		// Magnus Stone Weapons
		case 18533:		// Magnus Axe
		case 19168:		// Magnus Claymore
		case 19131:		// Magnus Dagger
		case 17047:		// Magnus Hammer
		case 19313:		// Magnus Lance
		case 18620:		// Magnus Pole
		case 18777:		// Magnus Sainti
		case 18967:		// Magnus Scythe
		case 18893:		// Magnus Sword
		case 18514:		// Magnus Toporok
		case 19289:		// Toki
		case 18456:		// Yoshihiro
			if(PAmmo->getID() == 19262)
			{
				if (WELL512::irand()%100 > 50)
				{
					// ShowDebug(CL_CYAN"Magnus Weapon Proc \n");
					if ( (PAmmo->getQuantity()-1) < 1) // ammo will run out after this attack, make sure we remove it from equip
					{
						uint8 slot = PChar->equip[SLOT_AMMO];
						charutils::UnequipItem(PChar,SLOT_AMMO);
						charutils::UpdateItem(PChar, LOC_INVENTORY, slot, -1);
					}
					else
					{
						charutils::UpdateItem(PChar, LOC_INVENTORY, PChar->equip[SLOT_AMMO], -1);
					}
					PChar->pushPacket(new CInventoryFinishPacket());
					originalDamage = (damage * 2);
				}
			}
			break;

		default:
			break;
	}

	switch (attackType)
	{
		case ZANSHIN_ATTACK:	if (WELL512::irand()%100 < PChar->getMod(MOD_ZANSHIN_DOUBLE_DAMAGE))		return originalDamage * 2;
		case TRIPLE_ATTACK:		if (WELL512::irand()%100 < PChar->getMod(MOD_TA_TRIPLE_DAMAGE))			return originalDamage * 3;
		case DOUBLE_ATTACK:		if (WELL512::irand()%100 < PChar->getMod(MOD_DA_DOUBLE_DAMAGE))			return originalDamage * 2;
		case RAPID_SHOT_ATTACK:	if (WELL512::irand()%100 < PChar->getMod(MOD_RAPID_SHOT_DOUBLE_DAMAGE))	return originalDamage * 2;
		case SAMBA_ATTACK:		if (WELL512::irand()%100 < PChar->getMod(MOD_SAMBA_DOUBLE_DAMAGE))		return originalDamage * 2;
		default: break;
	}
	return originalDamage;
}

/************************************************************************
*																		*
*  Try's to absorb MP from a physical attack.							*
*																		*
************************************************************************/

void TryAbsorbMPfromPhysicalAttack(CBattleEntity* battleEntity, uint32 damage)
{
	if (battleEntity->objtype != TYPE_PC)
	{
		return;
	}

	// Absorbs a percentage of damage to MP (100% rate)
	if (battleEntity->getMod(MOD_ABSORB_DMG_TO_MP) != 0)
	{
		uint16 absorbedMP = (float)(damage * battleEntity->getMod(MOD_ABSORB_DMG_TO_MP) / 100);
		battleEntity->addMP(absorbedMP);
		return;
	}
}

/************************************************************************
*																		*
*  Try's to absorb HP from a physical attack.							*
*																		*
************************************************************************/

bool TryAbsorbHPfromPhysicalAttack(CBattleEntity* battleEntity, uint32 damage)
{
	if (battleEntity->objtype != TYPE_PC)
	{
		return false;
	}

	// Do chance to absorb damage
	if (WELL512::irand()%100 < battleEntity->getMod(MOD_ABSORB_DMG_CHANCE))
	{
		return true;
	}

	// This needs reworked. Shouldn't be calling static item IDs anyway, do a mod for it.
	CItemArmor* PArmor = (CItemWeapon*)((CCharEntity*)battleEntity)->getEquip(SLOT_BACK);
	if (PArmor && PArmor->getID() == 10975) // Archon Cape 5% chance to annul "severe" physical damage
	{
		if ((ceil((float)(((float)damage / (float)battleEntity->GetMaxHP())) * 100)) > 50)
		{
			if (WELL512::irand()%100 <= 5)
			{
				return true;
			}
		}
	}
	return false;
}

}